C++OpenCV(3):基础交互(视频与鼠标操作)

您所在的位置:网站首页 opencv 鼠标移动 C++OpenCV(3):基础交互(视频与鼠标操作)

C++OpenCV(3):基础交互(视频与鼠标操作)

2024-02-02 19:00| 来源: 网络整理| 查看: 265

🔆 文章首发于我的个人博客:欢迎大佬们来逛逛 🔆 OpenCV项目地址及源代码:点击这里

文章目录 鼠标交互案例 视频读写交互视频(摄像头)转图像显示视频转图片并且保存摄像头转图片并保存 滑动条交互滑动条调整图片的亮度

鼠标交互

openCV中使用鼠标的交互的函数是:setMouseCallback

可以使得激活对winname为标题的窗口进行onMouse回调函数执行的鼠标交互操作,并且可以传递用户自定义变量给userdata

void setMouseCallback(const String& winname, MouseCallback onMouse, void* userdata = 0); /******************************************************************* * winname: 监听窗口名称 * onMouse: 鼠标事件回调函数 * userdata: 递给回调函数的可选参数 *********************************************************************/

关于MouseCallBack回调函数:

就是一个函数指针传递的参数必须一致:event鼠标点击事件, ∗ ∗ ( x , y ) ∗ ∗ **(x,y)** ∗∗(x,y)∗∗坐标,flag鼠标拖拽事件,void* 类型的param可以转为用户自定义变量。 typedef void (*MouseCallback)(int event, int x, int y, int flags, void* userdata); //MouseCallback onMouse void onMouse(int event,int x,int y,int flag,void *param) /******************************************************************* * event: 事件类型 * x: 鼠标所在图像的坐标 * y: * flags: 代表拖拽事件 * param: 自己定义的onMouse事件的ID *********************************************************************/

关于event和flag的枚举类型:

event:鼠标点击 enum MouseEventTypes { EVENT_MOUSEMOVE = 0, //鼠标移动 EVENT_LBUTTONDOWN = 1, //鼠标左键按下 EVENT_RBUTTONDOWN = 2, //鼠标右键按下 EVENT_MBUTTONDOWN = 3, //鼠标中键按下 EVENT_LBUTTONUP = 4, //鼠标左键弹起 EVENT_RBUTTONUP = 5, //鼠标右键弹起 EVENT_MBUTTONUP = 6, //鼠标中键弹起 EVENT_LBUTTONDBLCLK = 7, //鼠标左键双击 EVENT_RBUTTONDBLCLK = 8, //鼠标右键双击 EVENT_MBUTTONDBLCLK = 9, //鼠标中间双击 EVENT_MOUSEWHEEL = 10, //鼠标滚轮 正数和负数分别表示向前和向后滚动 EVENT_MOUSEHWHEEL = 11 //鼠标滚轮 正数和负数分别表示向右和向左滚动 }; flag:鼠标拖拽 enum MouseEventFlags { EVENT_FLAG_LBUTTON = 1, //左键拖动 EVENT_FLAG_RBUTTON = 2, //右键拖动 EVENT_FLAG_MBUTTON = 4, //中键拖动 EVENT_FLAG_CTRLKEY = 8, //ctr拖动 EVENT_FLAG_SHIFTKEY = 16, //shift拖动 EVENT_FLAG_ALTKEY = 32 //alt拖动 }; 案例

在一张图片中左键点击画圆,右键点击画矩形。

有关如何在openCV中绘制图形请参见:

OpenCV(2):图像处理基础概念与操作 | HugeYlh

关键之处就是要有一个鼠标回调函数:

可以声明为类的静态成员函数,然后利用params进行强制转换为本类类型。

接着判断event点击的事件进行绘制即可。

static void mouseEvent(int event, int x, int y, int flag, void* params) { DrawShape* obj = static_cast(params); if (event == cv::EVENT_FLAG_LBUTTON) { //左键画圆 obj->drawCircle(x, y, 20); } else if (event == cv::EVENT_FLAG_RBUTTON) { obj->drawRectangle(x, y, 20, 20); } }

然后在主程序中我们要激活这个回调函数,设置鼠标点击:

其中传递回调函数要使用函数指针的形式,即传递类的静态成员函数的地址。p表示我们需要传递自定义变量,以便在回调函数中params转换为我们需要操作的obj int main() { DrawShape* p = new DrawShape(); //鼠标处理过程 cv::namedWindow("mainWindow"); //typedef void (*MouseCallback) // (int event, int x, int y, int flags, void* userdata); cv::setMouseCallback("mainWindow", &DrawShape::mouseEvent, p); while (true) { p->show(); if (cv::waitKey(10) == 27) { break; } } delete p; p = nullptr; return 0; }

完整代码参见此Github项目

视频读写交互

使用openCV做视频操作可能不会如你想象的那么容易,因为openCV是一个强大的计算机视觉库,而不是专注于视频操作的多媒体库。

使用openCV做视频处理不能添加音频。

也许FFmpeg 库会满足你做多媒体开发的需求。

**VideoCapture**类型:对视频进行读取或者打开摄像头。

class VideoCapture { public: VideoCapture(); explicit VideoCapture(const String& filename, int apiPreference = CAP_ANY); explicit VideoCapture(const String& filename, int apiPreference, const std::vector& params); explicit VideoCapture(int index, int apiPreference = CAP_ANY); explicit VideoCapture(int index, int apiPreference, const std::vector& params); virtual ~VideoCapture(); virtual bool open(const String& filename, int apiPreference = CAP_ANY); virtual bool open(const String& filename, int apiPreference, const std::vector& params); virtual bool open(int index, int apiPreference = CAP_ANY); virtual bool open(int index, int apiPreference, const std::vector& params); virtual bool isOpened() const; virtual void release(); virtual bool grab(); virtual bool retrieve(OutputArray image, int flag = 0); virtual VideoCapture& operator >> (CV_OUT Mat& image); virtual VideoCapture& operator >> (CV_OUT UMat& image); virtual bool read(OutputArray image); virtual bool set(int propId, double value); virtual double get(int propId) const; String getBackendName() const; void setExceptionMode(bool enable) { throwOnFail = enable; } bool getExceptionMode() { return throwOnFail; } bool waitAny(const std::vector& streams,CV_OUT std::vector& readyIndex,int64 timeoutNs = 0); protected: Ptr cap; Ptr icap; bool throwOnFail; friend class internal::VideoCapturePrivateAccessor; };

读取一个视频:传递给视频的文件地址即可,如果我们传递了 0,则会打开摄像头(如果存在,否则报错)

cv::VideoCapture vap("cat.MP4"); if (!vap.isOpened()) { std::cout CAP_PROP_POS_MSEC =0, //视频文件的当前位置,单位为毫秒 CAP_PROP_POS_FRAMES =1, //解码/捕获的帧的基于0的索引 CAP_PROP_POS_AVI_RATIO =2, //视频文件的相对位置:0=影片开始,1=影片结束 CAP_PROP_FRAME_WIDTH =3, //视频宽度 CAP_PROP_FRAME_HEIGHT =4, //视频高度 CAP_PROP_FPS =5, //帧率 CAP_PROP_FOURCC =6, //4个字符的编解码器代码 CAP_PROP_FRAME_COUNT =7, //视频文件中的帧数 CAP_PROP_FORMAT =8, //视频格式 CAP_PROP_MODE =9, CAP_PROP_BRIGHTNESS =10, //图像亮度(摄像模式) CAP_PROP_CONTRAST =11, //图像对比度(摄像模式) CAP_PROP_SATURATION =12, //图像饱和度(摄像模式) CAP_PROP_HUE =13, //图像的色调(摄像模式) CAP_PROP_GAIN =14, //图像增益(摄像模式) CAP_PROP_EXPOSURE =15, //曝光(摄像模式) CAP_PROP_CONVERT_RGB =16, //图像是否应该转换为RGB的布尔标记 ....... };

例如:

void testProerity(cv::VideoCapture vap) { std::cout break;//为null则结束 } cv::imshow("cat", image); } vedio.release(); }

对于摄像头的转图片显示,我们只需要传递一个 VideoCapture xxx(0) 即可其他的全是一样的。

视频转图片并且保存

基本操作与上类似,只不过在**imshow**的地方我们改成了保存的操作(当然你也可以一边显示一边保存)

保存过程:imwrite函数

name:第一个参数表示保存的路径,传递前缀与文件名字与后缀来完成:cat/1.pngimage:保存的图片 void testCameraToPngImageSave(cv::VideoCapture vedio,std::string& prefilename) { cv::Mat image; int index = 1; while (true) { vedio >> image; if (image.empty() || cv::waitKey(10) == 27) { break; } std::string name = prefilename + std::to_string(index++) + ".png"; cv::imwrite(name, image); } vedio.release(); } 摄像头转图片并保存

如果是摄像头则我们不能用:imwrite

有一个**VideoWriter** 提供了这样的操作:通过创建一个VideoWriter类型的变量,然后通过 std::cout cap >> image; cv::imshow("摄像头", image); save TrackBar* obj = static_cast(params); cv::Mat copyMat = cv::Mat::zeros(obj->mt.size(), obj->mt.type()); int dims = obj->mt.channels(); float beta = 30, alpha = 0.1 + (float)pos / 10.0; for (int i = 0; i mt.rows; i++) { for (int j = 0; j mt.cols; j++) { if (dims == 1) { uchar pix = obj->mt.at(i, j); copyMat.at(i,j) = cv::saturate_cast(pix * alpha + beta); } else if (dims == 3) { cv::Vec3b vec = obj->mt.at(i, j); float b = vec[0], g = vec[1], r = vec[2]; copyMat.at(i, j)[0] = cv::saturate_cast(b * alpha + beta); copyMat.at(i, j)[1] = cv::saturate_cast(g * alpha + beta); copyMat.at(i, j)[2] = cv::saturate_cast(r * alpha + beta); } else { return; } } } cv::imshow("trackBarWindow", copyMat); //显示操作后的图像 }

完整代码详见Github项目源码。

https://github.com/luumod/openCV-learning-record



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3